package servlets;
import model.Course;
import model.Session;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URL;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import database.DBHandler;

public class Calendar extends AServlet {
	private static final long serialVersionUID = 1L;
	public final static String FS = System.getProperty("file.separator");
	
	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		
		HttpSession session = request.getSession();
		if (session == null || session.getAttribute("LoginStatus") == null
				|| !(Boolean) session.getAttribute("LoginStatus")) {
			response.sendRedirect("index.jsp");
			return;
		}
		
		if (request.getParameter("getStyle") == null){
			RequestDispatcher rd = getServletConfig().getServletContext()
			.getRequestDispatcher("/WEB-INF/JSP-Files/calendar.jsp");
			rd.forward(request, response);
			return;
		}
		getFormattedCalendar(request, response);
	}

	public void getFormattedCalendar(HttpServletRequest request,
			HttpServletResponse response) throws ServletException {
		PrintWriter out;
		try {
			out = response.getWriter();
		} catch (IOException e1) {
			e1.printStackTrace();
			return; //Nothing to do here. 
		}
		Connection con = DBHandler.getHandler().getLocalCon();
		String userName = (String) request.getSession().getAttribute("LoginName");
		ArrayList<Course> courses = null;
		try {
			courses = DBHandler.getHandler().getCoursesByUserName(userName, con);
		} catch (Exception e) {
			e.printStackTrace();
			finishTransaction(con, false);
			throw new ServletException();
		} 
		
		DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
		DocumentBuilder docBuilder = null;
		try {
			docBuilder = dbfac.newDocumentBuilder();
		} catch (Exception e) {
			e.printStackTrace();
			finishTransaction(con, false);
			throw new ServletException();
		} 
		
		Document doc = docBuilder.newDocument();
		Element timetableXML = doc.createElement("timetable");
		doc.appendChild(timetableXML);

		int[] skipHourTD = {0, 0, 0, 0, 0, 0, 0, 0};
		for(int i = 1; i <= 10; i++){
			Element hourXML = doc.createElement("hour");
			Attr numberHour  = doc.createAttribute("number");
			numberHour.setNodeValue(new String(""+i));
			hourXML.setAttributeNode(numberHour);
			for(int j = 1; j <= 7; j++){
				Element dayXML = doc.createElement("day");
				Attr numberDay  = doc.createAttribute("number");
				numberDay.setNodeValue(new String(""+j));
				dayXML.setAttributeNode(numberDay);
				if (skipHourTD[j] != 0){
					skipHourTD[j] -= 1;
					continue;
				}
				Element courseNameXML = doc.createElement("courseName");
				Element durationXML = doc.createElement("duration");
				Element startXML = doc.createElement("start");
				for (Course c : courses){
					ArrayList<Session> sessions = c.getSessions();
					boolean done = false;
					for (Session s : sessions){
						if (s.getDay() == j && s.getStart() == i){
							courseNameXML.appendChild(doc.createTextNode(c.getCourseName()));
							startXML.appendChild(doc.createTextNode(""+  s.getStart()));
							durationXML.appendChild(doc.createTextNode(""+ (s.getEnd() - s.getStart())));
							done = true;
							skipHourTD[j] = s.getEnd() - s.getStart() - 1;
							break;
						}
					}
					if (done)
						break;
				}
				dayXML.appendChild(courseNameXML);
				dayXML.appendChild(durationXML);
				dayXML.appendChild(startXML);
				hourXML.appendChild(dayXML);
			}
			timetableXML.appendChild(hourXML);
		}
		
		TransformerFactory transformerFactory = TransformerFactory
				.newInstance();
		try {
			Transformer transformerDOM2XML = transformerFactory
					.newTransformer();
			DOMSource source = new DOMSource(doc);
			StringWriter xml = new StringWriter();
			StreamResult result = new StreamResult(xml);
			transformerDOM2XML.transform(source, result);
			response.setContentType("text/html; charset=UTF-8");
			// Output goes to the response PrintWriter.
			StringWriter finalStringWriter = new StringWriter();
			TransformerFactory tFactory = TransformerFactory.newInstance();

			// get the real path for xml and xsl files.
			String ctx = getServletContext().getRealPath("") + FS;
			ByteArrayInputStream bs = new ByteArrayInputStream(xml.toString()
					.getBytes());
			Source xmlSource = new StreamSource(bs);
			Source xslSource = null;
			String style = new String(request.getParameter("getStyle"));
			if(style.equals("style1") || style.equals("style2")){
				xslSource = new StreamSource(new URL("file", "", ctx	+ 
						style+".xsl").openStream());
			}
			else{
				bs = DBHandler.getHandler().getUserStyle(userName, style, con);
				xslSource = new StreamSource(bs);
			}
			// Generate the transformer.
			Transformer transformer = tFactory.newTransformer(xslSource);
			// Perform the transformation, sending the output to the response.
			transformer.transform(xmlSource, new StreamResult(finalStringWriter));
			out.write(finalStringWriter.toString());
		}
		// If an Exception occurs, return the error to the client.
		catch (Exception e) {
			e.printStackTrace();
			finishTransaction(con, false);
			throw new ServletException();
		}
		
		finishTransaction(con, true);
		DBHandler.getHandler().returnLocalCon(con);
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException{
	    DiskFileItemFactory  fileItemFactory = new DiskFileItemFactory ();
		ServletFileUpload uploadHandler = new ServletFileUpload(fileItemFactory);
		Connection con = DBHandler.getHandler().getLocalCon();
		try { 
			List items = uploadHandler.parseRequest(request);
			Iterator itr = items.iterator();
			String fileName = null;
			String userName = (String) request.getSession().getAttribute("LoginName");
			FileItem item = null;
			while(itr.hasNext()) {
				item = (FileItem) itr.next();
				if (item.getFieldName().equals("xsltFile")){
					String[] pathElements = item.getName().split("\\\\");
					fileName = pathElements[pathElements.length - 1];
					break;
				}
			}
			DBHandler.getHandler().addStylesheet(userName,fileName,item.get(), con);
		} catch (Exception e) {
			e.printStackTrace();
			throw new ServletException();
		} 
		finally{
			finishTransaction(con, true);
			DBHandler.getHandler().returnLocalCon(con);
		}
	}
}
